import posixpath
import tools.ninja_syntax as ninja_syntax

TARGET = "X_INTF"

NINJA_SCRIPT_PATH = "build.ninja"

# debug build?
DEBUG = 1
# optimization
OPT = "-Og"

BUILD_DIR = "build"

PREFIX = "arm-none-eabi-"
CC = PREFIX + 'gcc'
AS = PREFIX + 'gcc -x assembler-with-cpp'
CP = PREFIX + "objcopy"
SZ = PREFIX + "size"

CPU = "-mcpu=cortex-m3"
MCU = [CPU, "-mthumb"]

LDSCRIPT = "STM32F103C8Tx_FLASH.ld"

ASDEFINES = []

CCDEFINES = [
    "USE_HAL_DRIVE",
    "STM32F103xB",
    "__RTTHREAD__",
    "__RT_KERNEL_SOURCE__",]

C_SOURCES = ["Src/main.c",
             "Src/gpio.c",
             "Src/spi.c",
             "Src/dma.c",
             "Src/stm32f1xx_it.c",
             "Src/stm32f1xx_hal_msp.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c",
             "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c",
             "Src/system_stm32f1xx.c",
             "Src/sysmem.c",
             "Src/syscalls.c",
             "components/aoaoutil/aoaoutil.c",
             "components/SEGGER_RTT/RTT/SEGGER_RTT.c",
             "components/SEGGER_RTT/RTT/SEGGER_RTT_printf.c",
             "rt-thread/src/klibc/kstdio.c",
             "rt-thread/src/klibc/kstring.c",
             "rt-thread/src/clock.c",
             "rt-thread/src/components.c",
             "rt-thread/src/cpu.c",
             "rt-thread/src/idle.c",
             "rt-thread/src/ipc.c",
             "rt-thread/src/irq.c",
             "rt-thread/src/kservice.c",
             "rt-thread/src/mem.c",
             "rt-thread/src/memheap.c",
             "rt-thread/src/mempool.c",
             "rt-thread/src/object.c",
             "rt-thread/src/scheduler_comm.c",
             "rt-thread/src/scheduler_up.c",
             "rt-thread/src/signal.c",
             "rt-thread/src/slab.c",
             "rt-thread/src/thread.c",
             "rt-thread/src/timer.c",
             "rt-thread/libcpu/arm/cortex-m3/cpuport.c",
             "rt-thread/components/finsh/cmd.c",
             "rt-thread/components/finsh/msh.c",
             "rt-thread/components/finsh/msh_file.c",
             "rt-thread/components/finsh/msh_parse.c",
             "rt-thread/components/finsh/shell.c",
             "application.c",
             "board.c",
             "fx_interface/fx_gpio.c",
             "fx_interface/fx_spi.c",
             "fx_interface/fx_power.c",
             "sources/fx_two.c",
             "sources/fx_base_loop.c",
             "sources/fx_aperture.c",
             "sources/fx_frame.c",
             "sources/fx_zoom.c",]

C_INCLUDES = [
    "Inc",
    "Drivers/STM32F1xx_HAL_Driver/Inc",
    "Drivers/STM32F1xx_HAL_Driver/Inc/Legacy",
    "Drivers/CMSIS/Device/ST/STM32F1xx/Include",
    "Drivers/CMSIS/Include",
    "components/aoaoutil",
    "components/SEGGER_RTT/RTT",
    "rt-thread/include",
    "rt-thread/components/finsh",
    "fx_interface",
    "sources",
]

ASM_SOURCES = [
    "startup_stm32f103xb.s",
]

ASMM_SOURCES = [
    "rt-thread/libcpu/arm/cortex-m3/context_gcc.S",
]

AS_INCLUDES = []

OBJ_OUT = []

CCFLAGS = []
CCFLAGS.extend(MCU)
CCFLAGS.append(OPT)
CCFLAGS.extend(["-Wall", "-fdata-sections", "-ffunction-sections"])

ASFLAGS = []
ASFLAGS.extend(MCU)
ASFLAGS.append(OPT)
ASFLAGS.extend(["-Wall", "-fdata-sections", "-ffunction-sections"])

if DEBUG == 1:
    CCFLAGS.extend(["-g", "-gdwarf-2"])

TARGET_ELF_PATH = posixpath.join(BUILD_DIR, TARGET + ".elf")
TARGET_MAP_PATH = posixpath.join(BUILD_DIR, TARGET + ".map")
TARGET_BIN_PATH = posixpath.join(BUILD_DIR, TARGET + ".bin")
TARGET_HEX_PATH = posixpath.join(BUILD_DIR, TARGET + ".hex")

LDFLAGS = []
LIBS = ["-lc", "-lm", "-lnosys"]
LIBPATH = []
LDFLAGS.extend(MCU)
LDFLAGS.extend(["-specs=nano.specs", "-T" + LDSCRIPT])
LDFLAGS.extend(LIBPATH)
LDFLAGS.extend(LIBS)
LDFLAGS.extend(
    ["-Wl,-Map={},--cref".format(TARGET_MAP_PATH), "-Wl,--gc-sections"])

f_ninja = ninja_syntax.Writer(open(NINJA_SCRIPT_PATH, mode="w+"), 80)

f_ninja.variable("build_dir", BUILD_DIR)

f_ninja.newline()

f_ninja.variable("CC", CC)
f_ninja.variable("AS", AS)
f_ninja.variable("CP", CP)
f_ninja.variable("SZ", SZ)

f_ninja.newline()


def rule_clean():
    f_ninja.rule("clean", "rm -rf {}".format(BUILD_DIR))
    f_ninja.newline()

################################################################################


def variable_make_cc():
    cc_flags_str = ""
    cc_includes_str = ""
    cc_defines_str = ""

    for s in CCFLAGS:
        cc_flags_str += s + " "

    for i in C_INCLUDES:
        cc_includes_str += "-I" + i + " "

    for d in CCDEFINES:
        cc_defines_str += "-D" + d + " "

    f_ninja.variable("ccflags", cc_flags_str)
    f_ninja.variable("cc_includes", cc_includes_str)
    f_ninja.variable("cc_defines", cc_defines_str)
    f_ninja.newline()


def rule_make_cc():
    cc_d = "-MMD -MP -MF$out.d"
    cc_lst = "-Wa,-a,-ad,-alms=$out.lst"
    f_ninja.rule(
        "cc", "$CC -c $ccflags $cc_defines $cc_includes {} {} $in -o $out".format(cc_d, cc_lst))
    f_ninja.newline()


def build_c_sources():
    for c in C_SOURCES:
        c_out = posixpath.join(BUILD_DIR, c.replace(".c", ".o"))
        OBJ_OUT.append(c_out)
        f_ninja.build(c_out, "cc", c)
    f_ninja.newline()

################################################################################


def variable_make_as():
    as_flags_str = ""
    as_includes_str = ""
    as_defines_str = ""

    for s in ASFLAGS:
        as_flags_str += s + " "

    for i in AS_INCLUDES:
        as_includes_str += "-I" + i + " "

    for d in ASDEFINES:
        as_defines_str += "-D" + d + " "

    f_ninja.variable("asflags", as_flags_str)
    f_ninja.variable("as_includes", as_includes_str)
    f_ninja.variable("as_defines", as_defines_str)
    f_ninja.newline()


def rule_make_as():
    as_d = "-MMD -MP -MF$out.d"
    as_lst = "-Wa,-a,-ad,-alms=$out.lst"
    f_ninja.rule(
        "as", "$AS -c $ccflags $cc_defines $cc_includes {} {} $in -o $out".format(as_d, as_lst))
    f_ninja.newline()


def build_asm_sources():
    for a in ASM_SOURCES:
        a_out = posixpath.join(BUILD_DIR, a.replace(".s", ".o"))
        OBJ_OUT.append(a_out)
        f_ninja.build(a_out, "as", a)

    for a in ASMM_SOURCES:
        a_out = posixpath.join(BUILD_DIR, a.replace(".S", ".o"))
        OBJ_OUT.append(a_out)
        f_ninja.build(a_out, "as", a)
    f_ninja.newline()

################################################################################


def variable_make_ld():
    ld_flags_str = ""

    for s in LDFLAGS:
        ld_flags_str += s + " "

    f_ninja.variable("ldflags", ld_flags_str)
    f_ninja.newline()


def rule_make_ld():
    f_ninja.rule(
        "ld", "$CC $in $ldflags -o $out")
    f_ninja.newline()


def build_ld_sources():
    f_ninja.build(TARGET_ELF_PATH, "ld", OBJ_OUT)

################################################################################


def rule_make_sz():
    f_ninja.rule("sz", "$SZ $in")


def build_size():
    f_ninja.build("size", "sz {}".format(TARGET_ELF_PATH))


def rule_make_exec():
    f_ninja.rule("hex", "$CP -O ihex $in $out")
    f_ninja.rule("bin", "$CP -O binary -S $in $out")


def build_exec():
    f_ninja.build(TARGET_HEX_PATH, "hex", TARGET_ELF_PATH, implicit="size")
    f_ninja.build(TARGET_BIN_PATH, "bin", TARGET_ELF_PATH, implicit="size")

################################################################################


variable_make_cc()
variable_make_as()
variable_make_ld()
rule_make_cc()
rule_make_as()
rule_make_ld()
rule_make_sz()
rule_make_exec()
rule_clean()
build_c_sources()
build_asm_sources()
build_ld_sources()
build_size()
build_exec()

f_ninja.build("clean", "clean")
f_ninja.build("build", "phony", TARGET_ELF_PATH)
f_ninja.build("hex", "phony", TARGET_HEX_PATH)
f_ninja.build("bin", "phony", TARGET_BIN_PATH)
f_ninja.default("build size hex bin")
f_ninja.newline()
